using System;
using UnityEngine;


namespace BF
{
    /// <summary>
    /// 计时器
    /// </summary>
    public sealed class Timer : ObjectRecycleItem
    {
        /// <summary>
        /// key唯一，当有相同key时，老Timer会直接停止
        /// </summary>
        public string key { get; private set; }
        /// <summary>
        /// 等待时间
        /// </summary>
        private float _delay;
        /// <summary>
        /// 等待条件为true
        /// </summary>
        private Func<bool> _delayFunc;
        /// <summary>
        /// action两次循环之间的等待时间
        /// </summary>
        private float _loopInterval;
        /// <summary>
        /// action循环次数
        /// </summary>
        private int _loopTimes;

        /// <summary>
        /// 是否已暂停计时器
        /// </summary>
        private bool _isPause;

        /// <summary>
        /// 第一次执行action的方法
        /// </summary>
        private Action _onStart;
        /// <summary>
        /// action
        /// </summary>
        private Action _onLoop;
        /// <summary>
        /// action循环结束的方法
        /// </summary>
        private Action _onComplete;

#if DEBUG
        internal System.Diagnostics.StackTrace popStackTrace;
#endif

        public Timer()
        {

        }

        internal void OnUpdate(float deltaTime)
        {
            if (_isPause)
            {
                return;
            }
            if (_delay > 0)
            {
                _delay -= deltaTime;
                if (_delay > 0)
                {
                    return;
                }
            }
            if (_delayFunc != null)
            {
                if (_delayFunc.Invoke())
                {
                    _delayFunc = null;
                }
                else
                {
                    return;
                }
            }

            _onStart?.Invoke();
            _onStart = null;

#if UNITY_EDITOR
            _onLoop?.Invoke();
#else
            try
            {
                _onLoop?.Invoke();
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
            }
#endif

            if (_loopTimes < 0) //无限循环
            {
                _delay += _loopInterval;
                return;
            }
            else if (_loopTimes <= 1)
            {
                _onComplete?.Invoke();
                _onComplete = null;

                this.Stop();
                return;
            }
            else
            {
                --_loopTimes;
                _delay += _loopInterval;
            }
        }

        /// <summary>
        /// key唯一，当有相同key时，老Timer会直接停止
        /// </summary>
        public Timer SetKey(string key)
        {
            this.key = key;
            return this;
        }

        /// <summary>
        /// 第一次执行Action的等待时间, 与<seealso cref="Delay(Func{bool})"/>互斥
        /// </summary>
        public Timer Delay(float firstDelay)
        {
            this._delayFunc = null;
            this._delay = firstDelay;
            return this;
        }

        /// <summary>
        /// 第一次执行等待条件true, 与<seealso cref="Delay(float)"/>互斥
        /// </summary>
        public Timer Delay(Func<bool> predicate)
        {
            this._delay = 0;
            this._delayFunc = predicate;
            return this;
        }

        /// <summary>
        /// 设置循环次数,循环次数-1则无限循环
        /// </summary>
        /// <param name="loopTimes">循环次数，-1则无限循环</param>
        /// <param name="loopInterval">循环间隔</param>
        public Timer Loop(int loopTimes, float loopInterval)
        {
            this._loopTimes = loopTimes;
            this._loopInterval = loopInterval;
            return this;
        }


        /// <summary>
        /// firstDelay后第一次执行，根据loopTimes判断是否循环执行
        /// </summary>
        public Timer Action(Action loopAction)
        {
            this._onLoop = loopAction;
            return this;
        }

        /// <summary>
        /// 使用<seealso cref="Action(System.Action)"/>代替
        /// </summary>
        [System.Obsolete]
        public Timer LoopAction(Action loopAction)
        {
            this._onLoop = loopAction;
            return this;
        }

        /// <summary>
        /// firstDelay后第一次执行，仅执行一次
        /// </summary>
        public Timer StartAction(Action startAction)
        {
            this._onStart = startAction;
            return this;
        }

        /// <summary>
        /// 所有循环Action结束后执行一次
        /// </summary>
        public Timer CompletionAction(Action completeAction)
        {
            this._onComplete = completeAction;
            return this;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public Timer Init(Action loopAction, float delay, float loopInterval, int loopTimes, Action completeAction, Action startAction)
        {
            return this.Init(string.Empty, loopAction, delay, loopInterval, loopTimes, completeAction, startAction);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public Timer Init(string key, Action loopAction, float delay, float loopInterval, int loopTimes, Action completeAction, Action startAction)
        {
            this.key = key;
            this._onLoop = loopAction;
            this._delay = delay;
            this._loopInterval = loopInterval;
            this._loopTimes = loopTimes;
            this._onStart = startAction;
            this._onComplete = completeAction;
            return this;
        }


        /// <summary>
        /// 计时器开始
        /// </summary>
        public void Execute()
        {
            TimerExecutor.instance.Execute(this);
        }

        /// <summary>
        /// 暂停或恢复计时器
        /// </summary>
        /// <param name="isPause"></param>
        /// <returns></returns>
        public void PauseOrResume(bool isPause)
        {
            this._isPause = isPause;
        }

        private new void ReturnToPool()
        {
            base.ReturnToPool();
        }

        /// <summary>
        /// 关闭计时器
        /// </summary>
        public void Stop()
        {
            //if (!this.isRecycled)
            {
                if (TimerExecutor.instance.Remove(this))
                {
                    this.ReturnToPool();
                }
            }
        }

        public override void OnRecycle()
        {
            key = string.Empty;

            _delay = 0;
            _delayFunc = null;
            _loopInterval = 0;
            _loopTimes = 0;

            _isPause = false;

            _onStart = null;
            _onLoop = null;
            _onComplete = null;

            base.OnRecycle();
        }

        #region Static

        /// <summary>
        /// Timer的全局TimeScale
        /// </summary>
        public static float timeScale = 1;
        /// <summary>
        /// 获取一个计时器
        /// </summary>
        public static Timer Pop()
        {
            Timer t = ObjectPool<Timer>.instance.Init().Pop();
#if DEBUG
            t.popStackTrace = new System.Diagnostics.StackTrace(true);
#endif
            return t;
        }

        /// <summary>
        /// 暂停或恢复所有计时器
        /// </summary>
        public static void PauseOrResumeAll(bool isPause)
        {
            TimerExecutor.instance.PauseOrResumeAll(isPause);
        }

        /// <summary>
        /// 暂停或者继续计时器
        /// </summary>
        /// <param name="key"></param>
        /// <param name="isPause">true:暂停计时器；false：继续计时器</param>
        public static void PauseOrResume(string key, bool isPause)
        {
            GetTimer(key)?.PauseOrResume(isPause);
        }

        /// <summary>
        /// 关闭计时器
        /// </summary>
        public static void Stop(string key)
        {
            GetTimer(key)?.Stop();
        }

        /// <summary>
        /// 根据key获取当前运行中的计时器，有可能空
        /// </summary>
        public static Timer GetTimer(string key)
        {
            return TimerExecutor.instance.GetTimer(key);
        }
        #endregion
    }
}
